Программирование сетевых приложений

Структурные механизмы языка программирования для реализации полиморфизма в программах

Программирование сетевых приложений

Содержание лекции

  • Интерфейсы и абстрактные классы
  • Механизм перегрузки функций
  • Механизм виртуальных функций
  • Перегрузка операций языка
  • Создание множественных определений
  • Многоуровневая структурированная иерархия классов
  • Расширение интерфейсов
  • Полиморфизм в Qt6
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Полиморфизм как структурный механизм

Определение

Полиморфизм - это возможность использовать объекты разных типов единым образом, обеспечивая гибкость и расширяемость программ.

Типы полиморфизма

  1. Статический (компиляционный) - перегрузка функций и операторов
  2. Динамический (исполнительный) - виртуальные функции и наследование
  3. Параметрический - шаблоны и обобщения
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Интерфейсы в C++

// Интерфейс для сетевого протокола
class INetworkProtocol {
public:
    virtual ~INetworkProtocol() = default;
    
    // Чисто виртуальные методы - контракт интерфейса
    virtual void connect(const string& address, int port) = 0;
    virtual void disconnect() = 0;
    virtual void sendData(const string& data) = 0;
    virtual string receiveData() = 0;
    virtual bool isConnected() const = 0;
};

// Интерфейс для шифрования
class IEncryption {
public:
    virtual ~IEncryption() = default;
    virtual string encrypt(const string& data) = 0;
    virtual string decrypt(const string& data) = 0;
    virtual string getAlgorithmName() const = 0;
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Реализация интерфейсов

// Реализация TCP протокола
class TcpProtocol : public INetworkProtocol {
private:
    bool connected;
    string serverAddress;
    int serverPort;
    
public:
    TcpProtocol() : connected(false), serverPort(0) {}
    
    void connect(const string& address, int port) override {
        serverAddress = address;
        serverPort = port;
        connected = true;
        cout << "TCP connection established to " << address << ":" << port << endl;
    }
    
    void disconnect() override {
        connected = false;
        cout << "TCP connection closed" << endl;
    }
    
    void sendData(const string& data) override {
        if (connected) {
            cout << "TCP sending: " << data << endl;
        }
    }
    
    string receiveData() override {
        return connected ? "TCP data received" : "";
    }
    
    bool isConnected() const override {
        return connected;
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Абстрактные классы и чисто виртуальные методы

// Абстрактный класс сетевого устройства
class NetworkDevice {
protected:
    string deviceId;
    string manufacturer;
    bool isActive;
    
public:
    NetworkDevice(const string& id, const string& maker) 
        : deviceId(id), manufacturer(maker), isActive(false) {}
    
    virtual ~NetworkDevice() = default;
    
    // Чисто виртуальные методы - делают класс абстрактным
    virtual void configure() = 0;
    virtual void start() = 0;
    virtual void stop() = 0;
    
    // Виртуальные методы с реализацией
    virtual string getDeviceInfo() const {
        return "Device: " + deviceId + " by " + manufacturer;
    }
    
    // Обычный метод
    void activate() { isActive = true; }
    void deactivate() { isActive = false; }
    bool getStatus() const { return isActive; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Конкретные реализации абстрактных классов

class Router : public NetworkDevice {
private:
    int portCount;
    vector<string> routingTable;
    
public:
    Router(const string& id, const string& maker, int ports) 
        : NetworkDevice(id, maker), portCount(ports) {}
    
    void configure() override {
        cout << "Configuring router with " << portCount << " ports" << endl;
        // Логика конфигурации маршрутизатора
    }
    
    void start() override {
        cout << "Starting router " << deviceId << endl;
        isActive = true;
    }
    
    void stop() override {
        cout << "Stopping router " << deviceId << endl;
        isActive = false;
    }
    
    void addRoute(const string& destination) {
        routingTable.push_back(destination);
    }
};

class Switch : public NetworkDevice {
private:
    int portCount;
    bool managed;
    
public:
    Switch(const string& id, const string& maker, int ports, bool isManaged) 
        : NetworkDevice(id, maker), portCount(ports), managed(isManaged) {}
    
    void configure() override {
        cout << "Configuring " << (managed ? "managed" : "unmanaged") 
             << " switch with " << portCount << " ports" << endl;
    }
    
    void start() override {
        cout << "Starting switch " << deviceId << endl;
        isActive = true;
    }
    
    void stop() override {
        cout << "Stopping switch " << deviceId << endl;
        isActive = false;
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Перегрузка функций

class NetworkService {
public:
    // Перегрузка по количеству параметров
    void connect() {
        cout << "Connecting to default server" << endl;
    }
    
    void connect(const string& server) {
        cout << "Connecting to server: " << server << endl;
    }
    
    void connect(const string& server, int port) {
        cout << "Connecting to " << server << ":" << port << endl;
    }
    
    // Перегрузка по типам параметров
    void sendData(const string& data) {
        cout << "Sending string data: " << data << endl;
    }
    
    void sendData(const vector<char>& data) {
        cout << "Sending binary data, size: " << data.size() << " bytes" << endl;
    }
    
    void sendData(int command) {
        cout << "Sending command: " << command << endl;
    }
    
    // Перегрузка с различными модификаторами const
    void processData() { cout << "Non-const processing" << endl; }
    void processData() const { cout << "Const processing" << endl; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Перегрузка операторов

class IPAddress {
private:
    string address;
    int subnetMask;
    
public:
    IPAddress(const string& addr, int mask = 24) : address(addr), subnetMask(mask) {}
    
    // Перегрузка оператора сравнения
    bool operator==(const IPAddress& other) const {
        return address == other.address && subnetMask == other.subnetMask;
    }
    
    bool operator!=(const IPAddress& other) const {
        return !(*this == other);
    }
    
    // Перегрузка оператора присваивания
    IPAddress& operator=(const IPAddress& other) {
        if (this != &other) {
            address = other.address;
            subnetMask = other.subnetMask;
        }
        return *this;
    }
    
    // Перегрузка оператора сложения для конкатенации IP-адресов
    IPAddress operator+(const IPAddress& other) const {
        return IPAddress(address + "." + other.address, subnetMask);
    }
    
    // Перегрузка оператора вывода
    friend ostream& operator<<(ostream& os, const IPAddress& ip) {
        os << ip.address << "/" << ip.subnetMask;
        return os;
    }
    
    // Перегрузка оператора индексации
    string operator[](int index) const {
        // Возвращаем октет IP-адреса по индексу
        vector<string> octets = split(address, '.');
        return (index >= 0 && index < octets.size()) ? octets[index] : "";
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Виртуальные функции и динамический полиморфизм

class NetworkProtocol {
public:
    virtual ~NetworkProtocol() = default;
    
    // Виртуальные методы
    virtual void establishConnection(const string& address, int port) {
        cout << "Basic connection establishment" << endl;
    }
    
    virtual void transmit(const string& data) {
        cout << "Basic data transmission" << endl;
    }
    
    virtual string receive() {
        return "Basic data reception";
    }
    
    // Чисто виртуальный метод
    virtual string getProtocolName() const = 0;
    
    // Виртуальный метод с реализацией по умолчанию
    virtual void closeConnection() {
        cout << "Basic connection closure" << endl;
    }
};

class HTTPProtocol : public NetworkProtocol {
public:
    void establishConnection(const string& address, int port) override {
        cout << "Establishing HTTP connection to " << address << ":" << port << endl;
    }
    
    void transmit(const string& data) override {
        cout << "Sending HTTP request: " << data << endl;
    }
    
    string receive() override {
        return "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html>...</html>";
    }
    
    string getProtocolName() const override {
        return "HTTP";
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Использование виртуальных функций

class FTPProtocol : public NetworkProtocol {
public:
    void establishConnection(const string& address, int port) override {
        cout << "Establishing FTP connection with authentication" << endl;
    }
    
    void transmit(const string& data) override {
        cout << "Sending FTP command: " << data << endl;
    }
    
    string receive() override {
        return "FTP response: 226 Transfer complete";
    }
    
    string getProtocolName() const override {
        return "FTP";
    }
    
    void closeConnection() override {
        cout << "FTP connection closed, logout completed" << endl;
    }
};

// Функция, использующая полиморфизм
void transferFile(NetworkProtocol* protocol, const string& filename) {
    cout << "Using protocol: " << protocol->getProtocolName() << endl;
    protocol->establishConnection("server.example.com", 80);
    protocol->transmit("GET " + filename);
    string response = protocol->receive();
    cout << "Response: " << response << endl;
    protocol->closeConnection();
}
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Множественные определения через перегрузку

class DataProcessor {
public:
    // Множественные определения для обработки разных типов данных
    
    // Обработка строк
    string process(const string& data) {
        return "Processed string: " + data;
    }
    
    // Обработка чисел
    int process(int number) {
        return number * 2;
    }
    
    // Обработка векторов
    vector<int> process(const vector<int>& data) {
        vector<int> result;
        for (int val : data) {
            result.push_back(val * val);
        }
        return result;
    }
    
    // Обработка сетевых пакетов
    NetworkPacket process(const NetworkPacket& packet) {
        NetworkPacket processed = packet;
        processed.timestamp = time(nullptr);
        processed.isValid = true;
        return processed;
    }
    
    // Обработка с различными параметрами
    string process(const string& data, const string& encoding) {
        return "Processed with " + encoding + ": " + data;
    }
    
    string process(const string& data, bool encrypt) {
        return encrypt ? "Encrypted: " + data : "Plain: " + data;
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Многоуровневая иерархия классов

// Базовый уровень - общее сетевое устройство
class NetworkDevice {
protected:
    string deviceId;
    bool isActive;
    
public:
    NetworkDevice(const string& id) : deviceId(id), isActive(false) {}
    virtual ~NetworkDevice() = default;
    
    virtual void start() = 0;
    virtual void stop() = 0;
    virtual string getDeviceType() const = 0;
    
    void activate() { isActive = true; }
    void deactivate() { isActive = false; }
};

// Второй уровень - IP-устройство
class IPDevice : public NetworkDevice {
protected:
    string ipAddress;
    string subnetMask;
    
public:
    IPDevice(const string& id, const string& ip) 
        : NetworkDevice(id), ipAddress(ip), subnetMask("255.255.255.0") {}
    
    virtual void configureIP(const string& ip, const string& mask) {
        ipAddress = ip;
        subnetMask = mask;
    }
    
    string getIPAddress() const { return ipAddress; }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Продолжение многоуровневой иерархии

// Третий уровень - маршрутизатор
class Router : public IPDevice {
protected:
    vector<string> routingTable;
    int interfaceCount;
    
public:
    Router(const string& id, const string& ip, int interfaces) 
        : IPDevice(id, ip), interfaceCount(interfaces) {}
    
    void start() override {
        cout << "Starting router " << deviceId << " with " << interfaceCount << " interfaces" << endl;
        activate();
    }
    
    void stop() override {
        cout << "Stopping router " << deviceId << endl;
        deactivate();
    }
    
    string getDeviceType() const override {
        return "Router";
    }
    
    void addRoute(const string& network, const string& gateway) {
        routingTable.push_back(network + " -> " + gateway);
        cout << "Route added: " << network << " via " << gateway << endl;
    }
    
    void configureIP(const string& ip, const string& mask) override {
        IPDevice::configureIP(ip, mask);
        cout << "Router IP configured: " << ip << "/" << mask << endl;
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Расширение интерфейсов

// Базовый интерфейс для сетевых служб
class INetworkService {
public:
    virtual ~INetworkService() = default;
    virtual void start() = 0;
    virtual void stop() = 0;
    virtual string getServiceName() const = 0;
};

// Расширенный интерфейс с возможностью конфигурации
class IConfigurableService : public INetworkService {
public:
    virtual ~IConfigurableService() = default;
    virtual void loadConfiguration(const string& configFile) = 0;
    virtual void saveConfiguration(const string& configFile) = 0;
    virtual bool validateConfiguration() const = 0;
};

// Интерфейс с мониторингом и логированием
class IMonitoredService : public INetworkService {
public:
    virtual ~IMonitoredService() = default;
    virtual ServiceStatus getStatus() const = 0;
    virtual vector<string> getLog() const = 0;
    virtual void clearLog() = 0;
    virtual int getErrorCount() const = 0;
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Комбинирование интерфейсов

// Класс, реализующий несколько расширенных интерфейсов
class WebServer : public IConfigurableService, public IMonitoredService {
private:
    bool isRunning;
    string configFile;
    vector<string> logs;
    int errorCount;
    ServiceStatus status;
    
public:
    WebServer() : isRunning(false), errorCount(0), status(ServiceStatus::STOPPED) {}
    
    // Реализация INetworkService
    void start() override {
        if (validateConfiguration()) {
            isRunning = true;
            status = ServiceStatus::RUNNING;
            log("Web server started");
        } else {
            log("Failed to start: invalid configuration");
            errorCount++;
        }
    }
    
    void stop() override {
        isRunning = false;
        status = ServiceStatus::STOPPED;
        log("Web server stopped");
    }
    
    string getServiceName() const override {
        return "WebServer";
    }
    
    // Реализация IConfigurableService
    void loadConfiguration(const string& file) override {
        configFile = file;
        log("Configuration loaded from " + file);
    }
    
    void saveConfiguration(const string& file) override {
        log("Configuration saved to " + file);
    }
    
    bool validateConfiguration() const override {
        return !configFile.empty();
    }
    
    // Реализация IMonitoredService
    ServiceStatus getStatus() const override {
        return status;
    }
    
    vector<string> getLog() const override {
        return logs;
    }
    
    void clearLog() override {
        logs.clear();
    }
    
    int getErrorCount() const override {
        return errorCount;
    }
    
private:
    void log(const string& message) {
        logs.push_back("[" + getCurrentTime() + "] " + message);
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Полиморфизм в Qt6 - метаобъектная система

#include <QObject>
#include <QMetaObject>
#include <QMetaMethod>

// Базовый класс с механизмом сигналов и слотов
class NetworkService : public QObject {
    Q_OBJECT
    
public:
    explicit NetworkService(QObject* parent = nullptr) : QObject(parent) {}
    
    // Виртуальные методы для полиморфного поведения
    virtual void startService() {
        qDebug() << "Starting basic network service";
        emit serviceStarted();
    }
    
    virtual void stopService() {
        qDebug() << "Stopping network service";
        emit serviceStopped();
    }
    
    virtual QString getServiceType() const = 0;
    
signals:
    void serviceStarted();
    void serviceStopped();
    void dataReceived(const QString& data);
    void errorOccurred(const QString& error);
    
public slots:
    virtual void processData(const QString& data) {
        qDebug() << "Processing data:" << data;
        emit dataReceived(data);
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Qt6 - конкретные реализации

class HttpService : public NetworkService {
    Q_OBJECT
    
public:
    explicit HttpService(QObject* parent = nullptr) : NetworkService(parent) {}
    
    void startService() override {
        qDebug() << "Starting HTTP service on port 80";
        emit serviceStarted();
    }
    
    void stopService() override {
        qDebug() << "Stopping HTTP service";
        emit serviceStopped();
    }
    
    QString getServiceType() const override {
        return "HTTP";
    }
    
public slots:
    void processData(const QString& data) override {
        qDebug() << "Processing HTTP request:" << data;
        QString response = "HTTP/1.1 200 OK\n\n" + data.toUpper();
        emit dataReceived(response);
    }
};

class FtpService : public NetworkService {
    Q_OBJECT
    
public:
    explicit FtpService(QObject* parent = nullptr) : NetworkService(parent) {}
    
    void startService() override {
        qDebug() << "Starting FTP service on port 21";
        emit serviceStarted();
    }
    
    QString getServiceType() const override {
        return "FTP";
    }
    
public slots:
    void processData(const QString& data) override {
        qDebug() << "Processing FTP command:" << data;
        emit dataReceived("226 Transfer complete");
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Qt6 - использование полиморфизма с сигналами и слотами

class ServiceManager : public QObject {
    Q_OBJECT
    
private:
    QList<NetworkService*> services;
    
public:
    ServiceManager(QObject* parent = nullptr) : QObject(parent) {}
    
    void addService(NetworkService* service) {
        services.append(service);
        
        // Подключение сигналов к слотам
        connect(service, &NetworkService::serviceStarted,
                this, &ServiceManager::onServiceStarted);
        connect(service, &NetworkService::dataReceived,
                this, &ServiceManager::onDataReceived);
        connect(service, &NetworkService::errorOccurred,
                this, &ServiceManager::onErrorOccurred);
    }
    
    void startAllServices() {
        for (NetworkService* service : services) {
            service->startService(); // Полиморфный вызов
        }
    }
    
    void processDataForAll(const QString& data) {
        for (NetworkService* service : services) {
            service->processData(data); // Полиморфный вызов
        }
    }
    
public slots:
    void onServiceStarted() {
        NetworkService* service = qobject_cast<NetworkService*>(sender());
        if (service) {
            qDebug() << "Service started:" << service->getServiceType();
        }
    }
    
    void onDataReceived(const QString& data) {
        NetworkService* service = qobject_cast<NetworkService*>(sender());
        if (service) {
            qDebug() << "Data from" << service->getServiceType() << ":" << data;
        }
    }
    
    void onErrorOccurred(const QString& error) {
        qDebug() << "Error:" << error;
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Qt6 - свойства и динамическое поведение

class ConfigurableService : public NetworkService {
    Q_OBJECT
    Q_PROPERTY(QString configFile READ configFile WRITE setConfigFile)
    Q_PROPERTY(bool autoStart READ autoStart WRITE setAutoStart)
    Q_PROPERTY(int maxConnections READ maxConnections WRITE setMaxConnections)
    
private:
    QString m_configFile;
    bool m_autoStart;
    int m_maxConnections;
    
public:
    explicit ConfigurableService(QObject* parent = nullptr) 
        : NetworkService(parent), m_autoStart(false), m_maxConnections(100) {}
    
    QString configFile() const { return m_configFile; }
    void setConfigFile(const QString& file) { m_configFile = file; }
    
    bool autoStart() const { return m_autoStart; }
    void setAutoStart(bool autoStart) { m_autoStart = autoStart; }
    
    int maxConnections() const { return m_maxConnections; }
    void setMaxConnections(int max) { m_maxConnections = max; }
    
    void startService() override {
        if (!m_configFile.isEmpty()) {
            loadConfiguration(m_configFile);
        }
        qDebug() << "Starting configurable service with max connections:" << m_maxConnections;
        emit serviceStarted();
    }
    
    QString getServiceType() const override {
        return "Configurable";
    }
    
private:
    void loadConfiguration(const QString& file) {
        qDebug() << "Loading configuration from:" << file;
        // Логика загрузки конфигурации
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Примеры использования полиморфизма в сетевом программировании

// Пример: обработка различных типов сетевых пакетов
class NetworkPacket {
public:
    virtual ~NetworkPacket() = default;
    virtual string getType() const = 0;
    virtual string serialize() const = 0;
    virtual void deserialize(const string& data) = 0;
    virtual size_t getSize() const = 0;
};

class TCPPacket : public NetworkPacket {
private:
    string sourceIP;
    string destIP;
    int sourcePort;
    int destPort;
    string payload;
    
public:
    string getType() const override { return "TCP"; }
    
    string serialize() const override {
        return sourceIP + ":" + to_string(sourcePort) + " -> " + 
               destIP + ":" + to_string(destPort) + " " + payload;
    }
    
    void deserialize(const string& data) override {
        // Парсинг TCP-пакета
        size_t pos = data.find(" -> ");
        if (pos != string::npos) {
            string src = data.substr(0, pos);
            string rest = data.substr(pos + 4);
            // Дальнейший парсинг...
        }
    }
    
    size_t getSize() const override {
        return sizeof(sourcePort) + sizeof(destPort) + 
               sourceIP.length() + destIP.length() + payload.length();
    }
};
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Паттерн "Фабрика" для создания полиморфных объектов

class PacketFactory {
public:
    static unique_ptr<NetworkPacket> createPacket(const string& type) {
        if (type == "TCP") {
            return make_unique<TCPPacket>();
        } else if (type == "UDP") {
            return make_unique<UDPPacket>();
        } else if (type == "HTTP") {
            return make_unique<HTTPPacket>();
        } else if (type == "FTP") {
            return make_unique<FTPPacket>();
        }
        return nullptr;
    }
    
    static vector<unique_ptr<NetworkPacket>> createPacketBatch(const vector<string>& types) {
        vector<unique_ptr<NetworkPacket>> packets;
        for (const auto& type : types) {
            auto packet = createPacket(type);
            if (packet) {
                packets.push_back(move(packet));
            }
        }
        return packets;
    }
};

// Использование фабрики
void processNetworkTraffic(const vector<string>& packetTypes) {
    auto packets = PacketFactory::createPacketBatch(packetTypes);
    
    for (const auto& packet : packets) {
        cout << "Processing " << packet->getType() << " packet" << endl;
        cout << "Size: " << packet->getSize() << " bytes" << endl;
        // Полиморфная обработка разных типов пакетов
    }
}
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Преимущества использования структурных механизмов полиморфизма

Гибкость и расширяемость

  • Возможность добавлять новые типы без изменения существующего кода
  • Единый интерфейс для различных реализаций

Повторное использование кода

  • Базовые классы содержат общую функциональность
  • Наследование позволяет переиспользовать код
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Упрощение сопровождения

  • Изменения в базовом классе автоматически распространяются на наследников
  • Четкое разделение интерфейса и реализации

Типобезопасность

  • Компилятор проверяет соответствие типов
  • Виртуальные функции обеспечивают безопасное приведение типов
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Рекомендации по использованию полиморфизма

1. Проектирование интерфейсов

  • Интерфейсы должны быть минимальными и специфичными
  • Используйте принцип разделения интерфейсов (ISP)

2. Использование виртуальных функций

  • Делайте деструкторы виртуальными в базовых классах
  • Используйте override для явного указания переопределения

3. Перегрузка функций

  • Избегайте неоднозначных перегрузок
  • Документируйте различия между перегруженными версиями

4. Управление памятью

  • Используйте умные указатели для полиморфных объектов
  • Помните о правиле трех/пяти/нуля

5. Производительность

  • Статический полиморфизм (шаблоны) может быть быстрее динамического
  • Виртуальные функции имеют небольшую накладные расходы
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Заключение

Основные структурные механизмы полиморфизма:

  1. Интерфейсы и абстрактные классы - определение контрактов
  2. Виртуальные функции - динамическая диспетчеризация
  3. Перегрузка функций - статический полиморфизм
  4. Перегрузка операторов - расширение возможностей типов
  5. Множественное наследование - комбинирование функциональности
  6. Шаблоны - параметрический полиморфизм

Применение в сетевом программировании:

  • Унификация работы с различными протоколами
  • Гибкая архитектура сетевых приложений
  • Расширяемость и сопровождаемость кода
  • Интеграция с Qt6 через метаобъектную систему
Структурные механизмы языка программирования для реализации полиморфизма в программах
Программирование сетевых приложений

Вопросы для самопроверки

  1. Чем отличаются интерфейсы от абстрактных классов в C++?
  2. Какие типы полиморфизма существуют и как они реализуются?
  3. Когда использовать виртуальные функции, а когда перегрузку?
  4. Как реализовать множественные определения для одной функции?
  5. Что такое чисто виртуальные методы и зачем они нужны?
  6. Как работает динамическая диспетчеризация методов?
  7. Какие преимущества дает использование полиморфизма в сетевом программировании?
  8. Как реализовать полиморфизм в Qt6 с использованием сигналов и слотов?
Структурные механизмы языка программирования для реализации полиморфизма в программах

Заметки докладчика: - Полиморфизм — одна из важнейших тем для сетевого программирования. Он позволяет писать код, не зависящий от конкретного протокола: через общий интерфейс можно работать с TCP, UDP, WebSocket и другими протоколами единообразно. - Обратите внимание: при проектировании сетевых приложений полиморфизм используется повсеместно — от обработки пакетов до реализации подключаемых модулей шифрования.

Заметки докладчика: - В C++ нет ключевого слова «interface» как в Java. Интерфейс в C++ — это класс, содержащий только чисто виртуальные методы (с = 0) и не имеющий полей данных. - Принятое соглашение: префикс «I» в имени (IConnectable, ISerializable, INetworkProtocol). - Деструктор интерфейса всегда должен быть виртуальным (virtual ~IName() = default), иначе при удалении через указатель на интерфейс не будет вызван деструктор производного класса.

Заметки докладчика: - Перегрузка (overload) разрешается на этапе компиляции — это статический полиморфизм. Не путайте с переопределением (override), которое работает в runtime. - Overload: одинаковое имя, разные параметры (количество или типы). - Override: совпадающая сигнатура в производном классе, вызов через vtable. - В сетевом программировании перегрузка удобна для API, принимающих разные форматы данных (строка, бинарный буфер, команда).

Заметки докладчика: - Перегружайте операторы только тогда, когда их смысл естественен и очевиден (== для сравнения, << для вывода, [] для индексации). - Всегда реализуйте перегрузку через открытый интерфейс класса, а не через внутренние поля. - Помните о правиле трёх/пяти: если перегружаете оператор присваивания, вероятно, нужны также деструктор и конструктор копирования (или перемещения).

Заметки докладчика: - Накладные расходы vtable: один указатель на объект (8 байт на 64-битной системе) + один косвенный вызов на каждый виртуальный метод. - Обычно это незначительно, но в критичных к производительности циклах (например, обработка тысяч пакетов в секунду) может иметь значение. - Используйте ключевое слово `final` для классов и методов, чтобы позволить компилятору выполнить девиртуализацию (devirtualization) — заменить косвенный вызов на прямой.

Заметки докладчика: - Паттерн «Фабрика» широко применяется в сетевом программировании для создания обработчиков протоколов. Пример: PacketFactory создаёт TCPPacket, UDPPacket на основе заголовка пакета. - Это позволяет добавлять новые протоколы без изменения клиентского кода — принцип открытости/закрытости (Open/Closed principle из SOLID). - В реальных проектах часто используют реестр: каждый протокол сам регистрирует свою фабричную функцию, что полностью устраняет необходимость модифицировать PacketFactory при добавлении нового типа.

Заметки докладчика: Ожидаемые ответы: 1. Интерфейс — класс только с чисто виртуальными методами и без полей данных. Абстрактный класс может иметь поля, обычные и виртуальные методы с реализацией по умолчанию. 2. Статический (перегрузка, шаблоны — на этапе компиляции), динамический (виртуальные функции — в runtime), параметрический (шаблоны/обобщения). 3. Виртуальные функции — когда поведение зависит от реального типа объекта в runtime. Перегрузку — когда нужно одинаковое имя для операций с разными параметрами, выбор на этапе компиляции. 4. Определить несколько функций с одним именем, но разными списками параметров (разное количество, типы или модификаторы const). 5. Метод с "= 0" — не имеет реализации в базовом классе, делает класс абстрактным. Производный класс обязан его переопределить. 6. Через таблицу виртуальных функций (vtable) — указатель на vtable хранится в каждом объекте, вызов происходит через косвенную адресацию. 7. Единый интерфейс для разных протоколов (TCP/UDP/WebSocket), расширяемость без изменения существующего кода, упрощение тестирования (моки через интерфейсы). 8. Наследовать от QObject, использовать Q_OBJECT, объявлять виртуальные слоты в базовом классе и переопределять их в производных, связывать сигналы со слотами через connect().